`co(4,7);───────────────────── Welcome to EnQue's EnCom V1.60 ─────────────────────────`co();
`tab(2);`color_default(LIGHTGRAY,BLUE);`color_keyword(YELLOW,BLUE);`color_first_char(WHITE,BLUE);

          `keyword(Using EnQue Help, Using This Help);             `keyword(16550 UART Support, EnCom 16550 UART);
          `keyword(Introduction, An Introduction to);                 `keyword(CRC & Message Formatting, CRC and Message);
          `keyword(Getting Started, Beginning);              `keyword(New Debugging Support!, Debugging Support);
          `keyword(Design Concepts, EnCom Design);              `keyword(Library Naming Conventions, Library Naming);
          `keyword(How EnCom Works, EnCom Mechanics);              `keyword(EnCom Library Reference, The EnCom Library);
          `keyword(Flow Control, Flow Control);

  
  Press `co(15,?);[Tab]`co();, the arrow keys, or the first letter of the keyword to move
  the cursor to the desired topic, and press `co(15,?);[Enter]`co();.
`co(15,?);
  To order the large model libraries, complete source code and printed
	documentation, send a check or money order for $99.95 to the address
	below.  Orders from outside the USA please add $10.00 for additional
	shipping and handling costs.
`co();
  We recommend you page through and read all of this documentation, using
  the hypertext features to move to and from topics of interest.`co();

`co(4,7);───────────────────────── Using This Help System ────────────────────────────`co();

    This help system is part of EnQue's UltraWin and InTUItion libraries,
  and was designed for useful hypertext systems.  We use it for the disk-
  based documentation for our products.  Using the help system is very
  easy.  Simply use the keypad cursor keys to move around the help.  You
  can also position the cursor on a keyword and press `co(15,?);[Enter]`co(); to move
  quickly to the section that deals with that keyword.  Keywords for this
  documentation show up like this `co(15,1);K`co(14,1);eyword`co();.  To move back to the previous
  section, simply press the `co(15,?);[Backspace]`co(); key.

    If you have a mouse, you can double-click on keywords, grab the scroll
	bars at the right and bottom of the help window, or click on any of the
	buttons.  The buttons can also be used by pressing `co(15,?);ALT-KEY`co();, where `co(15,?);KEY`co(); is
	the highlighted letter.

		If you are a Borland DOS-based IDE user, you can load our tiny TCKBD.COM
	TSR.  This 4k routine allows you to invoke our help engine from the
	Integrated Environment, searching for the function/keyword on which the
	cursor resides, in much the same way as Borland's help.  To do this, you
	must setup our help engine as a Transfer program.  See your Borland manual
	for details.  Include on the command line the $NOSWAP macro so that our
	help will overlay and restore the current window.  A typical command line
	from within the transfer editor for EGA/VGA 43/50 row mode for ENQHELP.EXE
	might look like this: `co(15,?);"$NOSWAP ENCOMREF.HLP 1 0 2 2 77 40"`co();. The first
	numeric parameter is set to 1.  This tells the help engine to call our TSR
	to get the string at the current cursor location, and use that as the
	search string.  The next is a user search string (just use 0 to tell the
	engine no command line search string), and the next four numeric
	parameters are the screen coordinates start x, start y, end x, and end y.
	These last four parameters are optional.  A window of the default size
	will be created if they are omitted.

	  You may also run the help engine directly from the command line,
	removing the $NOSWAP macro.  You need not load TCKBD.COM to do this.
	(TCKBD.COM merely allows the help engine to read the word that your cursor
	is currently pointing to - it does not ever have to be loaded, it merely
	adds functionality).

`co(4,7);───────────────────────── An Introduction to EnCom ───────────────────────────`co();

    Welcome to the EnCom library, `keyword(version 1.60, Version History); (C) 1992-94 EnQue Software!
  EnCom provides the PC programming community with a powerful tool for
  developing communications applications.  The EnCom library is written in
  100% portable C and supports the Borland, Microsoft, and Zortech families
  of compilers, and now with 1.60, Watcom C/C++32 under DOS4G in flat memory
  model.  Now you can write multi-megabyte applications under protected mode
  as well as 640K DOS programs!
  See `keyword(disclaimer,Disclaimer); for legal information on using the library.

  For information about this or other EnQue products, please contact us at:

       `co(14,?);EnQue Software                  Fax/Voice: (816) 987-2515
       Route 1, Box 116C               24 Hr BBS: (816) 353-0991
       Pleasant Hill, MO 64080             Kevin: (816) 540-5709
                                            Boyd: (816) 353-5561`co();
`co(15,?);
  To order the large model libraries, complete source code and printed
	documentation, send a check or money order for $99.95 to the address
	above.  Orders from outside the USA please add $10.00 for additional
	shipping and handling costs.

`co(4,7);────────────────────────────── Disclaimer ────────────────────────────────────`co();

    EnCom is a user supported communications library for the IBM PC.  EnCom
	is copyrighted material.  However, we distribute the small model libraries
	and disk-based documentation at no charge.  We do this so that you can
	actually use the library to be sure it suits your needs before purchasing
	the product.  Please feel free to give the small model libraries and
	disk-based documentation to whomever you wish.  You are also free to
	distribute any executables generated with EnCom royalty free.

	  Under no conditions may you duplicate or distribute the EnCom large
	model libraries or EnCom source code without the prior written consent of
	EnQue Software.

	  Purchasing the commercial version provides you not only with large model
	libraries and complete source code, but also free technical support and
	software upgrades through the EnQue BBS.

    The authors have taken great care in preparing this disk-based manual
	and accompanying programs and data, including research, development, and
	testing.  The authors make no expressed or implied warranty of any kind
	with regard to the software or accompanying documentation.  In no event
	shall the authors or EnQue Software be liable for incidental or
	consequential damages in connection or arising out of the performance or
	use of any part of this product.

`co(4,7);────────────────────────────── Version History ───────────────────────────────`co();

  07/10/92  --  Version 1.00
    The initial release of the EnCom library.  The demo programs, demo
		source, documentation and the small model versions of the library for
		the Turbo/Borland/Microsoft C compilers were released to the public.

  01/10/93 -- Version 1.50
		The powerful SOURCE_TRACE debugging feature was added.  Encom will now
		detect and report nearly all questionable parameters, eliminating much
		of your debugging effort!

  05/01/94 -- Version 1.60
		Support for Watcom C/C++32 under DOS4G was added, giving you the 
		capability of writing programs no longer bound by the 640K DOS limit!

`co(4,7);──────────────────────── Beginning an EnCom Project ─────────────────────────`co();

    When you begin an EnCom project, simply include the file ENCOM.H in each
	of the C modules that need access to EnCom.  When specifying the files to
	link, be sure to include the appropriate library.  The EnCom files are
	described as follows: 

  ENCOM.H 
   	The main header file.  It contains all the structures, globals and
		defines you will need to reference in your source files.  Always include
		this file. 

    `co(15,?);Very Important Note:
    If you have several C files for your project, include a `co(14,?);#define ENCOM 1`co(15,?);
  	at the very top of all but the main C file, before the inclusion of
		ENCOM.H.  The main C module (without the #define) will then contain the
		global variables for EnCom, and all other modules will contain external
		references to those globals.  If you are using UltraWin and/or InTUItion
		with EnCom, or have only one C file that needs to reference EnCom, this
		is not necessary!`co();
  	 	  
  ENTS.LIB 
  	This is the small model library for Borland's Turbo C 2.0.  This library
		is compatible with Turbo C 2.0,  Turbo C++, and Borland C++, under the
		normal C compiler. 
  	 	  					 
  ENMS.LIB 
  	This is the small model library for Microsoft C, compiled with 
  	Microsoft Visual C (C version 8.0).

  ENZS.LIB 
  	This is the small model library for Zortech C, compiled with Zortech C
		1.50.

  `co(15,?);Starting with Turbo/Borland C`co();
	    If you are using any Borland product under the integrated environment,
		simply open a project file, and include the START.C file along with the
		ENTS.LIB library, set the compiler model to small and select "Build All"
		to build the program.  If you wish to use the command line compiler,
		type the following for Turbo C:
	  `co(11,?);tcc -G -O -Z -r -d -ms -r -estart.exe start.c ents.lib`co();
		and the following for Borland C:
	  `co(11,?);bcc -G -O -Z -r -d -ms -r -estart.exe start.c enbs.lib`co();
	 
	`co(15,?);Starting with Microsoft C`co();
	 	  If you are using the command line compiler, simply compile START.C
		under small model.  We recommend turning off stack checking (/Gs) and
		using byte-aligned structures (/Zp).  The command line is as follows:
	  `co(11,?);cl /Gs /Zp /Os /AS start.c /Festart.exe /link /ST:8192 enms.lib`co();
	 	 
  `co(15,?);Sarting with Watcom C32`co();
	 	 	Use the ENQRBLD.EXE program included to rebuild the flat model
		library for EnCom.  Then use the following command line to make the
		START.EXE under flat model with the DOS4G extender.
	  `co(11,?);wcl386 start.c /k8192 /l=dos4g /fe=start.exe enwf.lib`co();

  `co(15,?);Sarting with Zortech C`co();
	 	 	Compile the file START.C for small model.  You must include the -a
		parameter for byte-aligned structures.  The command line is as follows:
	  `co(11,?);ztc -a -b =9000 -msi start.c enzs.lib -ostart.exe`co();


`co(4,7);────────────────────────── EnCom Design Concepts ─────────────────────────────`co();

    The EnCom library was designed around several key concepts, which we
  feel separates EnCom from other libraries of its type.  Please note that
  we assume some working knowledge of PC communications.  Our documentation
  would unfortunately triple in size if we covered all aspects, making it
  more difficult to understand.  If you need more information on the 8250
  UART, modem control, etc. refer to your computer or modem manual, or a
  text pertaining to PC communications.

  Press `co(15,?);[Tab]`co(); or the arrow keys to move the cursor to the desired concept,
  and press `co(15,?);[Enter]`co();.

  `keyword(Small Code Size,1. Small);
  `keyword(100% Portable C,2. 100%);
  `keyword(Ease of Use,3. Ease);
  `keyword(Rich in Features,4. Rich);
  `keyword(Sample C Code,5. Sample C);
  
  `co(15,?);1. Small Code Size:`co();
       The library must be very small, consisting of as few functions as are
     necessary to accomplish a well-rounded comm toolbox.  Many other
     products boast of hundreds of functions, many of which are redundant,
     and some of which are just unnecessary.  We try to concentrate on
     making the library lean and mean, and work hard on eliminating fluff.
     As a result the library is very powerful, but is only about 16K in
     size!
  
  `co(15,?);2. 100% Portable C`co();
       The library must be 100% portable C.  This may come as a real
     surprise to many.  If you don't think 100% C can be small and fast then
     you must take a look at our text windowing library UltraWin, or our
     user interface library InTUItion!  In real terms, the only function
     within the library that should even be considered as an assembler
     candidate is the interrupt routine itself.  However, with efficient C
     coding and today's optimizing compilers, the speed of the C code is
     within a few percent of the assembly version.  We discovered this after
     hours of hand-optimizing the assembly code for the interrupt routine,
     and then comparing its performance against a carefully optimize C
     interrupt routine.  The extra few percent gained is not worth the loss
     in portability.  Another reason to strive for 100% C is that you the
     customer can more easily understand and if needed modify the code,
     thereby making the product more usable.  And if you wish to port the
     code to another CPU or another platform, your job will be much easier
     without assembly headaches.  In addition, by taking advantage of the
     fast memory move capabilites of the PC and FIFO (first in, first out)
     capabilities of UARTs such as the 16550, speeds as high as 115,000
     Kbaud are readily attainable, all in 100% C, and even on older PC's.
  
  `co(15,?);3. Ease of Use`co();
       The library must be very easy to use.  The first two concepts make
     this an easily attainable target.  By keeping the library in 100% C,
     and concentrating on more functionality with less code, the learning
     curve for EnCom is measured in minutes and hours, not days and weeks as
     is the case with many of our competitors.  Functions are concise, well
     documented, clearly named, and intuitive in nature.  The bottom line is
     that if a function is not needed, it is not in our library.
  
  `co(15,?);4. Rich in Features`co();
       The library must be very rich in features, yet easy to learn.  It
     has always been our belief that the best solution to a problem is
     usually the least complex solution.  When carefully thought out, a
     simple solution can be both functional and elegant.  Contrary to what
     many companies believe, it is possible to have a small, concise, easy
     to learn library and yet be rich in features.  The following are just
     a few examples of what we have been able to put into EnCom!

         A)  `co(12,?);Fully interrupt driven transmit and receive`co(); with queues up to
             64K in size, and a `keyword(queue status,EnCom's "Queue Status"); mode where each character is
             queued along with the current line status register, allowing a
             character by character look at errors.
         B)  `co(12,?);Interrupt handlers`co(); for line/modem control and break.
         C)  Support for `co(12,?);`keyword(Comm 1-4,Comm 1-4 Support); and FIFO'ed UARTs`co(); such as the 16550.
         D)  Enhanced keyboard control such as `co(12,?);Ctrl-C and Ctrl-Break
             handling`co();.  This feature takes control from the OS and places
             it in your hands.
         E)  `co(12,?);Timer and sound support`co();.  Enhanced timing resolution and
             interrupt-driven time events is crucial to comm software, yet
             so many libraries leave this feature out.  In addition, control
             of the PC speaker is provided, and can be automatically turned
             off via the timer interrupt.
         F)  `co(12,?);CRC generation and message formatting/encryption routines.`co();
             Perhaps no other library offers these features.  EnCom can
             generate CRC's based on any polynomial, including the CRC-16
             and CCITT standards.  In addition, message formatting routines
             are included that greatly simplify custom communications
             between two PC's.  These routines are explained in more detail
             later.  Needless to say, if you have data to send between two
             machines, you will fall in love with these routines!
  
  `co(15,?);5. Sample C code to begin using immediately`co();
       Two programs with full source are included.  The first and simplest
     is only a few dozen lines yet implements full bidirectional
     communications and can be used to dial a BBS.  If ANSI.SYS is loaded
     into your system, it will even emulate an ANSI terminal.  This program,
     called START.C, shows how simple using EnCom really is.  Just type
     START with an optional port and baud rate (default is COM1 at 2400
     baud).  To use COM2 at 1200 baud, type `co(15,?);START 2 1200`co(); and press
     `co(15,?);[Enter]`co();.
    
       The second program is a "testbed" for EnCom and shows the use of most
		 of EnCom's macros and functions.  This program uses UltraWin for
		 display, so many functions will seem unfamiliar.  However, the code is
		 very straightforward.  This program, COM_DEMO.C, takes the same
		 optional parameters as START.C.  Once running, you may press Alt-H for
		 a list of function keys and what they do.  One thing to keep in mind
		 here is that it won't seem like anything happens when many keys are
		 pressed.  This is the nature of manipulating comm hardware.  For
		 instance, toggling the DTR line won't show much unless you have a
		 breakout box hooked to the port.  Ideally, you will hook this to
		 another machine or "loop" it back to itself so that anything sent is
		 received.  While we are on that subject, the PC UART has a built-in
		 diagnostics loopback mode which can be set by calling `keyword(com_232_ctrl,[ENCOMREF.HLP]/// com_232_ctrl);.
		 However, when this mode is activated, all the modem control lines are
		 "disconnected" from the outside world, including OUT2.  OUT2 is used by
		 many comm boards to "mask" interrupts from the UART.  Therefore, when
		 placed in loopback mode, nothing is sent or received.  You will notice
		 though that "toggling" the control lines such as DTR or RTS will show a
		 corresponding change on DSR and CTS.  This is a very important point.
		 If you ever enable LOOP (it is disabled automatically by the init
		 functions), you will more than likely lose interrupt capability!
       
       Also, to show you the power of the library, we have included a
     powerful communications program in its own right.  The terminal
     application supplied illustrates the use of EnCom functions, and
     contains `co(12,?); VT100 terminal emulation, upload and download ASCII,
     Xmodem Checksum, Xmodem CRC, and Ymodem protocols.`co();

       This mini-application also demonstrates the power of our sister
		 products, UltraWin and InTUItion, and was written in just a few weeks
		 using the three libraries.  To start the program, just type TD and
		 press `co(15,?);[Enter]`co();.  This defaults to 2400 baud on COM2.  To change the port
		 and baud rate from the command line, type the additional parameters
		 just as in START.C.  For example, to use a modem on COM1 at 1200 baud,
		 just type `co(15,?);TD 1 1200`co(); and press `co(15,?);[Enter]`co();.  After the program comes up,
		 you can press ALT-Z for help.

       Note that the executable is only about 100K even though it uses the
		 low-level windowing library, the higher-level user interface library, a
		 powerful hypertext help engine, and, of course, EnCom, not to mention
		 the complete VT100 emulation and file transfer protocols and all the
		 standard C stuff!  `co(12,?);Most competing comm libraries are larger than
		 this complete application!`co();

     `co(15,9);NOTE: Complete source code is included on purchase of EnCom!`co();
  
`co(4,7);─────────────────────────── Comm 1-4 Support ─────────────────────────────────`co();

	  EnCom supports comm ports 1-4.  However, due to hardware limitations
	with most PC's, there can only be one device active on a given interrupt.
	COM1 and COM3 typically share IRQ 4 while COM2 and COM4 typically share
	IRQ 3.  Therefore, only two ports can be operating simultaneously, ports
	1 and 2, 1 and 4, 2 and 3, or 3 and 4.  You cannot operate COM1 and COM3
	or COM2 and COM4 at the same time.

    If your comm board allows the use of non-standard interrupts (like IRQ 5
	or IRQ 7), it is possible to run all four ports concurrently.  Simply call
	com_config to specify an alternate base address or IRQ before calling
	com_port_create.  See `keyword(com_config,[ENCOMREF.HLP]/// com_config); for more information. 

`co(4,7);───────────────────── EnCom Mechanics and Interrupts ─────────────────────────`co();

    The most important routine in any communications library is the comm
  interrupt routine.  It comprises the heart of the entire library.  It is
  in this routine that all data is received and transmitted.  All other
  functions merely help you get the data into and out of the transmit and
  receive queues.
  
    The interrupt routine has three primary tasks:
    
    1)  `keyword(Receive,The Receive Interrupt); data from the UART.
    2)  `keyword(Transmit,The Transmit Interrupt); data to the UART.
    3)  `keyword(Watch,Interrupt Status); the control lines and break status.
    
  Of these three, the first two are the most critical, and by nature the
  most complex.

`co(4,7);───────────────────────── The Receive Interrupt ──────────────────────────────`co();

    When the UART receives a character, it generates an interrupt.  The
	interrupt routines sees that this is a new character and must decide what
	to do with it.  First it checks to see if there are any errors (i.e.
	parity, framing or overrun).  If there is an error, it increments the
	appropriate counter in the port structure.  It then checks to see if
	`co(15,?);XON/XOFF`co(); handshaking is being used.  If it is in use, it checks to see if
	the character was an XOFF and if so, turns the transmitter off.  If not,
	it checks to see if the character was an XON character.  If so, it resumes
	transmission.  Next, it checks to see if adding the character to the
	receive queue will cause the queue to hit its "highwater" mark.  The
	"highwater" mark is a user-definable number that when hit makes the
	interrupt tell the other system "I have all the data I can safely take for
	now".  If this condition is met, the interrupt routine sends an XOFF
	character to the other system, thereby temporarily halting its
	transmission.  Finally, if the character is not processed by the above
	flow control, it is stored into the receive queue.
	
	  This may sound somewhat complicated, but it is really quite simple.
	Basically, data is received and stored in the receive queue, and if the
	queue starts to get full, we tell the other system to "hang on a minute".
	Likewise, we check to see if the other system is telling us to "hang on
	a minute", so we do not fill up its queue.  Keep in mind that both
	systems can send and receive data simultaneously!


`co(4,7);───────────────────────── The Transmit Interrupt ─────────────────────────────`co();

    The transmit interrupt handling is much simpler than the receive
  interrupt, as it only has to do a simple check.  If no flow control is
  in use, we simply send the byte.  If `co(15,?);XON/XOFF`co(); is in use, we check to
  see if transmission is temporarily suspended, and if so do nothing.
  Otherwise, we send the next byte in the transmit queue.

`co(4,7);─────────────────── Interrupt Status and Line Control ────────────────────────`co();

    When the line status (DSR, DCD, CTS, RI) changes, an interrupt is
  generated.  The status of each of the lines is stored as a separate bit
  in the port status variable.  By storing in this manner, you can
  utilize the variable to find out if any of the lines have changed over
  a period of one or many characters.  We provide a comprehensive set of
  macros that allow you to determine the state of these lines directly,
  or if the state has changed since you last checked.  Several methods
  of flow control can be handled here as well, see `keyword(Flow Control, Flow Control ); for
  more information.
  
    When a "break" condition is sensed, the interrupt routine simply 
  increments the break counter in the port structure.  The user application
  can check this variable to determine if a break condition has occured.

`co(4,7);───────────────────────────────── Flow Control ──────────────────────────────`co();

    EnCom provides several methods of flow control.  The following lists
  the flow control types supported by EnCom.
  
  `co(15,?);XON/XOFF`co();
  	Perhaps the most common flow control, a bidirectional software method
	as described above in `keyword(Receive,The Receive Interrupt);.  The primary drawback to XON/XOFF
	is that there must be two unique characters that will not be used for
	anything else, thereby preventing the reception and transmission of binary
	data.

  `co(15,?);DCR/DCD`co();
    Unlike XON/XOFF, this is a hardware flow control.  It works as follows:
	First, if DCD (Data Carrier Detect) flow control is enabled, all incoming
	data will be ignored unless DCD is asserted (Logic 1).  The same option is
	available using the DSR (Data Set Ready Line).  These two lines can be
	used in combination, requiring that both be asserted for data to be
	received. These modes are set with the functions `keyword(set_dcd_flow,[ENCOMREF.HLP]/// set_dcd_flow); and
	`keyword(set_dsr_flow,[ENCOMREF.HLP]/// set_dsr_flow);.

  `co(15,?);RTS/CTS`co();
    RTS/CTS (Request-to-send / Clear-to-send) handshaking is another form of
	hardware flow control.  This is a half-duplex method and is not commonly
	used with modern communications equipment, but is included for
	compatibility.  Here's how it works.  When data needs to be transmitted,
	the system asserts RTS.  The data communications equipment senses this,
	finishes what it's doing (sending data), and asserts the CTS line.  When
	we see the CTS line go high, we send our data.  When we are through, we
	drop the RTS line to tell the communications equipment that we are
	through.  Use the `keyword(set_cts_flow,[ENCOMREF.HLP]#define set_cts_flow); macro for this flow control.

  `co(15,?);High Speed RTS/CTS`co();
 		This is a bidirectional RTS/CTS method, sometimes referred to as RTR/CTS
 	(ready-to-receive / clear-to-send).  This is set by using the same
  `keyword(set_cts_flow,[ENCOMREF.HLP]#define set_cts_flow); macro as RTS/CTS, but passing the #define HS_RTS_CTS instead
	of ON.  This flow control method, as used by many high speed modems, works
	as follows:  When the receiving system can accept data, it sets RTS (RTR)
	high, telling the transmitting equipment that it is ready to receive.
	This is set when the receive queue is below the "lowwater" mark as set by
	the `keyword(set_lowwater,[ENCOMREF.HLP]#define set_lowwater); macro.  When the receive queue reaches the "highwater"
	mark, as set by the `keyword(set_highwater,[ENCOMREF.HLP]#define set_highwater); macro, it drops RTR, telling the
	transmitting equipment to "hold on".  When the transmitting equipment
	needs to send data, it waits until the CTS line goes high.  It then
	transmits until the CTS line drops low.  This is similar to the standard
	RTS/CTS method but the lines remain independent; the transmitter never
	issues a request-to-send, it merely checks the state of the CTS line. This
	method is probably the best handshaking method available, since XON/XOFF
	is limited to ASCII data and the others are not bidirectional. Its use
	is recommended wherever possible.

		Computer                                                   Modem
 		---------                                                  -------
    RTS (RTR) --->--- computer tells modem it's ready --->--- CTS
    CTS       ---<--- modem tells computer it's ready ---<--- RTS (RTR)


		That's about it.  Other methods can be used but are not "built into" the
	library.  Complete control over the modem control lines is only a macro or
	function call away!

`co(4,7);────────────────── EnCom's "Queue Status" Receive Mode ───────────────────────`co();

    EnCom has the ability to queue the line status register with every
  character received.  This can be enabled or disabled at any time using
  the `keyword(set_queue_status,[ENCOMREF.HLP]#define set_queue_status); macro.  When enabled, the character is queued
  followed by the status.  The status byte is an exact copy of the UART's
  line status register and can be checked using the masks defined in
  ENCOM.H.  These are as follows:
	`co(12,?);
	/*-------------------- line status register bit masks ------------------*/
	#define DR	 	 0x01					/* data ready														 0	*/
	#define OE 		 0x02					/* overrun error												 1	*/
	#define PE	 	 0x04					/* parity error 												 2	*/
	#define FE 		 0x08					/* framing error 												 3	*/
	#define BI 		 0x10					/* break interrupt											 4	*/
	#define THRE	 0x20					/* transmitter holding register empty		 5	*/
	#define TSRE	 0x40					/* transmitter shift   register empty		 6	*/
	#define F_ERR  0x80					/* FIFO error (only for 16550)           7	*/
	`co();  

		Keep in mind that when enabled, the receive queue will require twice the
	space to store a given number of characters.  Also, when extracting data
	from the queue using `keyword(com_getc,[ENCOMREF.HLP]/// com_getc); and `keyword(com_getc_qty,[ENCOMREF.HLP]/// com_getc_qty); the status information
	is removed as well.  See these routines for more information.

`co(4,7);─────────────────────── CRC and Message Formatting ───────────────────────────`co();

    EnCom's CRC generation functions provide much more than just support
  for X/Ymodem CRC calculation.  CRC in general is an excellent way to
  verify the integrity of serially transmitted data.  The EnCom routines
  will support the generation of CRC's for any polynomial, including the
  standard CRC-16 and CRCCITT standards, in both forward and reverse modes.
  The standard method, forward CRCCITT with preset 0's, is used by
  X/Ymodem and will suffice for most needs.
  
    Many of you are probably wondering what "message formatting" routines
  are.  Just sit back and follow along, because chances are, you will find
  a use for these after you finish reading this section.  The best way to
  describe this facility is to show you an example.
  
    Joe at Weather Systems, Inc. takes data readings from several different
  instruments every 10 seconds 24 hours a day.  The equipment that came
  with the instruments included a PC board that just plugged into his
  computer, and some lab-type software written in C that gives him access
  to the numbers from each of the instruments.  Joe wrote a program that
  "snapshots" the data every 10 seconds, and stores it in a structure.  The
  structure looks like this:
  
  typedef struct wdata_struct
  {
    int     wind_speed;
    int     wind_direction;
    int     temp;
    int     humidity;
    double  rainfall;
    double  pressure;
    long    timedate;
  } WDATA;
  
    Ok, so Joe has his data in a nice little structure, and he can log these
	structures to disk for storage.  The problem arises when Joe's boss, Dick,
	tells him that he needs the data to be transmitted over a lease line to
	Dan at the Chicago office 24 hours a day.  The boss also wants the data
	transmitted as fast as the modem will allow, namely 9600 baud.  He also
	wants the data encrypted, so that if anyone is watching the line, they
	won't know what the data is.  So how does Joe do this?  Joe knows he needs
	some sort of ending character that will mark the end of a structure, but
	since he is sending doubles, ints, and longs, how can he guarantee the end
	character he chooses is not in the structure?  That would really mess
	things up.  Things get even more complicated when Dick tells Joe he wants
	another structure sent every few seconds that is a whole set of different
	variables, and whatever algorithm he uses must be able to send any other
	structures defined later.  What does Joe do (besides quit)?
  
	  Joe wishes he had a function that would just take any structure and
	transmit it without having to worry about all the ugly details.  Then
	he reads about EnCom's message facilities and this sparks his interest.
	After reading about the function `keyword(fmt_msg,[ENCOMREF.HLP]/// fmt_msg); he raises his hands to the sky
	and does a little dance.  The function is exactly what he needs.
	
	  The fmt_msg function encapsulates any data into a unit called a
	"message".  A message is a data packet that contains the data in a
	"quoted" format followed by a two-byte CRC and a unique ending flag
	character.  So what does this mean?
	
	  Quoting a message is a process by which undesired characters that are
	within the data are translated into a two-character sequence that does
	not contain an undesired character.  This is necessary if we wish to
	have a message that does not contain our end flag character.  This
	is how Joe's problem of having the end flag character a part of
	his structure is resolved.  See `keyword(quoting,Quoting Mechanics); for specific details.

    Once fmt_msg quotes and encrypts the data, it then calculates the CRC
	for the entire message, and appends the two bytes to the end of the
	message. Finally, the end flag character is tagged on and the message can
	be transmitted by calling `keyword(com_putc_qty,[ENCOMREF.HLP]/// com_putc_qty);.  It's that simple!

    When the receiving system in Chicago gets the data, it checks for the
  unique ending flag character as a mark of the end of the packet.  It
  then pulls the entire message out of the port receive queue, (end-flag to
  end-flag), knows that the last two bytes are the CRC, and calculates the
  CRC on all but the last two bytes.  It then compares it to the transmitted
  CRC and if they do not match, it pitches the message.  To encapsulate
  all this, we give you a little function called get_msg that does all
  the decryption, dequoting, and CRC checking for you!
  
    Select `keyword(example,A Specific Example); for a run-through of the process EnCom goes through
  when fmt_msg and get_msg are used.

`co(4,7);──────────────────────────── Quoting Mechanics ───────────────────────────────`co();

    To "quote" a message, we simply check for an end flag character, and
	when found, replace it with the quote flag character 0x88, followed by the
	end flag character "exclusive or'ed" with the quote mask character 0x11.
	This installs a two-byte sequence that cannot contain the original end
	flag character.  Since the quote flag itself marks a two-byte sequence,
	then any occurences of that character must also be quoted to a two-byte
	sequence, just like the end flag. This end flag can be set to whatever
	character you wish, although it is a good idea to select a character that
	does not appear very often in the type of data you are sending to avoid
	expanding the data by a significant amount. (It must not be 0x88 or 0x11).

`co(4,7);──────────────────────────── A Specific Example ──────────────────────────────`co();

  /*----------------------------- Joe's Code ------------------------------*/
	int len;
	PORT  Port;															/* Joe's channel 1 port struct	 */
	WDATA wdata;														/* where the data is stored      */
  uchar buffer[sizeof(WDATA)*2+5];				/* make sure we have enough room */
  ...																			/* init code goes here					 */
  `keyword(set_encrypt,[ENCOMREF.HLP]#define set_encrypt);(0x21,&Port);								 /* set encryption character      */
  `keyword(set_match,[ENCOMREF.HLP]#define set_match);(0xf0,&Port);									 /* set match (end_flag) character*/
  `keyword(init_msg,[ENCOMREF.HLP]#define init_msg);(&Port);												/* tell functions about chars		 */

	while( 1 )
	{
		get_data(&wdata);											/* Joe's function to get the data*/
		len = `keyword(fmt_msg,[ENCOMREF.HLP]/// fmt_msg);((uchar *) &wdata,       /* format the message            */
		              buffer, sizeof(WDATA));
	  `keyword(com_putc_qty,[ENCOMREF.HLP]/// com_putc_qty);(buffer, len, &Port);			/* send the data to Chicago 		 */
	}

  /*----------------------------- Dan's Code ------------------------------*/
	int len;
	PORT  Port;															/* Dan's channel 3 port struct	 */
	WDATA wdata;														/* where the data is stored      */
  uchar buffer[sizeof(WDATA)*2+5];				/* make sure we have enough space*/
  ...																			/* init code goes here					 */
  `keyword(set_encrypt,[ENCOMREF.HLP]#define set_encrypt);(0x21,&Port);								 /* set encryption character      */
  `keyword(set_match,[ENCOMREF.HLP]#define set_match);(0xf0,&Port);									 /* set match (end_flag) character*/
  `keyword(init_msg,[ENCOMREF.HLP]#define init_msg);(&Port);												/* tell functions about chars    */
	
	while( 1 )
	{
		if( `keyword(msg_cnt,[ENCOMREF.HLP]#define msg_cnt);(&Port) )                  /* is there a message available? */
		{
			if( !(len = `keyword(get_msg,[ENCOMREF.HLP]/// get_msg);(buffer,&Port)) )/* if so, go get it							*/
				printf("Error\r\n");							/* if 0 returned, there an error */
			movmem(buffer, &wdata, len);				/* get copy into structure			 */
			print_data(&wdata);                 /* Dan's print routine					 */
			save_data(&wdata);									/* Dan's save routine						 */
		}
	}

	  Note that we get the message into a temporary buffer; this is because
	the two byte CRC is extracted into the message.  This is due to the fact
	that we don't yet know it's the CRC until the end_flag is hit.  This two
	byte CRC is not included in the count, however.  If the CRC fails, get_msg
	returns a 0, otherwise the length is returned.  That's all there is to it!

`co(4,7);─────────────────────── EnCom 16550 UART Support ─────────────────────────────`co();

		EnCom fully supports the 16550AF and 16550AFN UARTs.  The library will
	automatically detect the type of UART in your system (8250, 16450, 16550)
	and enable the FIFO's for you.  You can override this with the provided
	macros.  There are many varieties and revisions to the UARTs used in PC's.
	Most older 8088 based system use the 8250.  AT variety machines with their
	somewhat higher speed used the 8250A or 16450 (both detected as a 16450).
	These are functionally identical to the 8250 except for faster access time
	and a single scratchpad register.  The 16550 in it's original variety was
	"buggy" and the FIFO's were not useable; EnCom detects this as a 16450,
	thereby disabling the FIFO's.  The 16550AF and 16550AFN are generally not
	found in most machines due to their higher cost; however, if you are doing
	high speed communications or need that little extra performance edge,
	these parts are the way to go.  They can reduce transmit interrupt
	overhead by nearly 16 to 1, and receive interrupt overhead by nearly the
	same, depending on the receive trigger level set.  As stated, these parts
	are automatically sensed and enabled.  The receive trigger is defaulted to
	8 but can be set to 1, 4, 8, or 14 using the `keyword(com_fifo_trigger,[ENCOMREF.HLP]/// com_fifo_trigger); function.
	Another function, `keyword(com_fifo_ctrl,[ENCOMREF.HLP]/// com_fifo_ctrl);, allows enabling/disabling the FIFO's as
	well as clearing them.  It is recommended that the macros we provide for
	FIFO control be used as opposed to calling com_fifo_ctrl yourself.

	  NOTE: Even though the 16650 generates an interrupt every "x" characters,
	if the FIFO trigger level is not reached and no data has been received
	for 4 character times, a "timeout" interrupt will be generated and the
	remaining bytes will be extracted; a wonderful feature of the 16550!

`co(4,7);────────────────────── The EnCom Library Reference ───────────────────────────`co();

    The EnCom library is composed of both `keyword(macros,EnCom Macros); and `keyword(functions,[ENCOMREF.HLP]EnCom Functions);.  To keep
  the library small, any functionality that takes one line or less of C
  code is implemented with a macro.  Some of the macros simply call one
  of the functions with the proper parameters.  Many of the modem commands
  are implemented in this manner.   Other macros serve to "hide" the port
  structure.
  
  	The EnCom library has a few global variables that may be used in special
  cases.  For more information see `keyword(Structures and Globals,EnCom Structures);.


`co(4,7);───────────────────── EnCom Structures and Globals ───────────────────────────`co();

    The only structure definition used by EnCom is the PORT structure.  It
  is used by nearly every function in the library.  It should never be
  necessary to access the structure directly, as the functions and macros
  we provide handle all the details for you.  See `keyword(ENCOM.H,[ENCOM.H]ENCOM.H); for details.

	  Several global variables may be used in special cases.  They are as
	follows:
	`co(12,?);  
  int   Tics_per_sec;							/* ~ tics/second of clock interrupt		 */
	char  Pause_char = '~';         /* pause character used by modem_cmd 	 */
	char  Clear_rx_char = '<';			/* clear rx que char used by modem_cmd */
	char  Clear_tx_char = '>';      /* clear tx que char used by modem_cmd */
	uchar Encrypt_char = 0x35;      /* encryption character used by msg'ing*/
	uchar End_flag = 0xf0;          /* end flag character used by msg'ing  */
	`co();
  The Encrypt_char and End_flag are set by calling the macros set_encrypt
  and set_match, followed by init_msg.  Do not change Tics_per_sec as this
  is set by init_clock. The other variables can be changed as needed.


`co(4,7);─────────────────────────────── EnCom Macros ─────────────────────────────────`co();

    The EnCom macros add excellent capability to the EnCom libarary.  We
	employ an OOP technique and do a little "information hiding" for you.
	Basically, we try to provide you with an easy to understand macro to
	access all the port structure variables that you might need.  While you
	can do this directly, there is no guarantee that the results will be what
	you expect, or that we will never modify the structure.  Therefore, by
	providing you with macro access, the code size remains small and you
	don't have to worry about the details of the data structures.  However, if
	you don't find a macro to do what you need, feel free to access the data
	structure; better yet, write a macro and let us know about it!  The macros
	are divided into categories for ease of reference.  These are:
  
  `keyword(General Macros,[ENCOMREF.HLP]EnCom General Mac);            `keyword(Comm Macros,[ENCOMREF.HLP]EnCom Com);       `keyword(Message Macros,[ENCOMREF.HLP]EnCom Mes);
  `keyword(Handshaking Macros,[ENCOMREF.HLP]EnCom Hand);        `keyword(Modem Macros,[ENCOMREF.HLP]EnCom Mod);      `keyword(Line Status Macros,[ENCOMREF.HLP]EnCom Line);
  `keyword(16550 Support Macros,[ENCOMREF.HLP]EnCom 16550);

    In addition, the modem and line status macros come in two basic types.
	The "immediate" type determines the state at the time of the macros
	execution, while the "static" type informs you of a state change since the
	last clear macro was executed.  These allows you to check for the current
	status, as well as changes in status over time.  The static type uses a
	variable in the port structure, that gets "or'ed" with the appropriate bits
	on interrupt, and is ideal for block mode checking.

`co(4,7);────────────────────────────── Debugging Support ─────────────────────────────`co();

                          `co(15,?);"Source Trace" Libraries!`co();

    Starting with version 1.50, EnCom has included powerful debugging
	facilities.  The libraries come in two "flavors", the smaller standard
	production libraries, and the `co(15,?);Source Trace`co(); libraries.  The
	Source Trace libraries are used for development, and the standard 
	production libraries for the finished product.
  
    When using the Source Trace libraries, EnCom will check the validity of
	most function parameters.  The most important of these are pointers to
	EnCom's PORT structure.  EnCom can detect when you pass an invalid or
	uninitialized pointer to a function and will popup an error window stating
	the function that detected the error and the invalid pointer.  You can
	choose to exit the program in a safe and orderly manner, or continue.  If
	you continue, do so at your own risk; you may merely overwrite memory that
	has no effect, but you may also write over memory outside of your program
	space and cause all sorts of nasty things, a "lockup" being the least of
	these!

    EnCom also checks many other parameters, including parameters withing
	your macros!  The macros that are used for many EnCom operations are
	replaced with functions in the Source Trace versions of the library.  This
	gives you parameter validation for what normally is handled by the
	preprocessor.
  
    The error window shows a call log that displays the last 64 EnCom
	functions, the file and line number where they where called, and a count
	of how many times they were called.  A call stack shows the internal calls
	made by EnCom.  For instance, if get_msg calls com_getc and com_getc
	detects and reports the error, the call stack will show that get_msg
	called com_getc. The com_getc call will not be placed in the call log
	since it was not called by your program.  You can use the cursor keys to
	scroll up and down through the call log.  The top entry (entry 1) is the
	oldest.  Even more exciting than the call log is the fact that the error
	window can even display the offending line in your source code!

    If you choose to exit when an error occurs, EnCom will call exit(0).
	exit() will close all open files, including files you have opened, and
	will call all functions that are "registered" using atexit().  This
	function allows you to "register" functions to be called by exit and is an
	excellent cleanup technique.  Refer to you compiler's documentation for
	further details.  EnCom registers the end_clock() and end_ctrlc_hldr()
	functions that correspond to init_clock and init_ctrlc_hdlr().  These are
	all called automatically if you exit.

    To use the Source Trace libraries, simply link in the appropriate
	library for your compiler, and define SOURCE_TRACE at the top of your "C"
	file, before the inclusion of "encom.h".  Most compilers will allow you to
	define it globally for a project, or at least give you the ability to
	define it on the compilers command line.  Defining SOURCE_TRACE allows the
	error window to display the line number of the file, the name of the file
	in which the error was found, and even "pull up" the offending line from
	the "C" file, if it is found in the current directory!  If you do not
	define SOURCE_TRACE, but use the Source Trace version of the library, then
	the error reporting will still be active, but no line number or file
	information will be displayed and macro parameters will not be checked.

    When you are satisfied with your program, it is recommended that you
	relink with the standard production library.  This will reduce code size
	and increase performance.

`co(4,7);────────────────────────── Library Naming Conventions ────────────────────────`co();

    EnCom supports many different compilers, and now with the Source Trace
  feature the number of possible libraries has multiplied greatly.  To
  make it easier to know which library goes with what compiler, we have
  adopted a simple library naming convention.

    The first two letters of the library indicates the product, and are the
  letters `co(15,?);EN`co(); for EnCom.  The next letter(s) indicates the compiler,
  as shown below:

    Compiler                Letters
    ─────────────────────   ────────   
    Turbo C                 `co(15,?);T`co();
    Turbo C++               `co(15,?);TCP`co();
    Borland C               `co(15,?);B`co();
    Borland C++             `co(15,?);BCP`co();
    Microsoft C             `co(15,?);M`co();
    Microsoft C++           `co(15,?);MCP`co();
    Watcom C                `co(15,?);W`co();
    Watcom C++              `co(15,?);WCP`co();
    Mix Power C             `co(15,?);X`co();
    Zortech C               `co(15,?);Z`co();
    Zortech C++             `co(15,?);ZCP`co();

  The next letter indicates the library model, and is:

    Model                   Letter
    ─────────────────────   ────────   
    Small                   `co(15,?);S`co();
    Medium                  `co(15,?);M`co();
    Compact                 `co(15,?);C`co();
    Large                   `co(15,?);L`co();
    Flat                    `co(15,?);F`co(); (Watcom C/C++32 only)

  Finally, if the library is a Source Trace "debug" version, the letter `co(15,?);D`co();
	is appended.
  
    For example, the large model standard production library for Turbo C
	would be `co(15,?);ENTL.LIB`co();, the small model Source Trace library for Turbo C would
	be `co(15,?);ENTSD.LIB`co();, and the compact model Source Trace library for Borland C++
	would be `co(15,?);ENBCPCD.LIB`co();.
